/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.classes.controller;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import lombok.AllArgsConstructor;

import javax.validation.Valid;

import org.springblade.common.annotation.ServiceLog;
import org.springblade.common.constant.TrainingOperateConstant;
import org.springblade.common.exception.TrainingServiceException;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.CollectionUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.ObjectUtil;
import org.springblade.modules.classes.bo.UserBindingBo;
import org.springblade.modules.classes.entity.*;
import org.springblade.modules.classes.excel.ClassesScoreExcel;
import org.springblade.modules.classes.excel.TrainingPlanReusltExcel;
import org.springblade.modules.classes.service.*;
import org.springblade.modules.classes.wrapper.ClassesPlanWrapper;
import org.springblade.modules.course.service.ICourseService;
import org.springblade.modules.material.entity.PaperAnswerEntity;
import org.springblade.modules.material.entity.PaperReleaseEntity;
import org.springblade.modules.material.entity.ReleaseExamUserEntity;
import org.springblade.modules.material.service.IAnswerService;
import org.springblade.modules.material.service.IPaperReleaseService;
import org.springblade.modules.material.service.IReleaseExamUserService;
import org.springblade.modules.material.vo.PaperAnswerVO;
import org.springblade.modules.material.wrapper.AnswerWrapper;
import org.springblade.modules.personal.entity.UserBaseEntity;
import org.springblade.modules.personal.service.IUserBaseService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.modules.classes.vo.ClassesVO;
import org.springblade.modules.classes.excel.ClassesExcel;
import org.springblade.modules.classes.wrapper.ClassesWrapper;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.excel.util.ExcelUtil;
import org.springblade.core.tool.constant.BladeConstant;
import springfox.documentation.annotations.ApiIgnore;

import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;

/**
 * 班级表 控制器
 *
 * @author junxin
 * @since 2023-04-28
 */
@RestController
@AllArgsConstructor
@RequestMapping("blade-classes/classes")
@Api(value = "班级表", tags = "班级表接口")
public class ClassesController extends BladeController {

	private final IClassesService classesService;
	private final IClassesUserService classesUserService;
	private final IClassesPlanService classesPlanService;
	private final ITrainingPlanService trainingPlanService;
	private final IPaperReleaseService paperReleaseService;
	private final IUserBindingService userBindingService;
	private final IAnswerService answerService;
	private final ITrainingPlanCourseService trainingPlanCourseService;
	private final ICourseService courseService;

	/**
	 * 班级表 详情
	 */
	//@PreAuth(TrainingRoleConstant.HAS_ROLE_TEACHER)
	@GetMapping("/detail")
	@ApiOperationSupport(order = 1)
	@ApiOperation(value = "详情", notes = "传入classes")
	public R<ClassesVO> detail(ClassesEntity classes) {
		ClassesEntity detail = classesService.getOne(Condition.getQueryWrapper(classes));
		ClassesVO classesVO = ClassesWrapper.build().entityVO(detail);
		classesVO.setStudents(classesUserService.count(Wrappers.<ClassesUserEntity>query().lambda().eq(ClassesUserEntity::getClassesId, classesVO.getId())));

		ClassesPlanEntity classesPlanEntity = classesPlanService.
			getOne(Wrappers.<ClassesPlanEntity>query().lambda().eq(ClassesPlanEntity::getClassesId, classesVO.getId()));
		if (null != classesPlanEntity) {
			TrainingPlanEntity trainingPlanEntity = trainingPlanService.getById(classesPlanEntity.getPlanId());
			if (null != trainingPlanEntity) {
				classesVO.setTrainingPlanName(trainingPlanEntity.getPlanName());
				classesVO.setClassesPlan(ClassesPlanWrapper.build().entityVO(classesPlanEntity));
				classesVO.setTrainPlanId(trainingPlanEntity.getId());
			}
		}
		return R.data(classesVO);
	}

	/**
	 * 班级表 分页
	 */
	@GetMapping("/list")
	@ApiOperationSupport(order = 2)
	@ApiOperation(value = "分页", notes = "传入classes")
	public R<IPage<ClassesVO>> list(@ApiIgnore @RequestParam Map<String, Object> classes, Query query) {
		IPage<ClassesEntity> pages = classesService.page(Condition.getPage(query), Condition.getQueryWrapper(classes, ClassesEntity.class));
		IPage<ClassesVO> classesVOIPage = ClassesWrapper.build().pageVO(pages);
		classesVOIPage.getRecords().forEach(vopage -> {
			vopage.setStudents(classesUserService.count(Wrappers.<ClassesUserEntity>query().lambda().eq(ClassesUserEntity::getClassesId, vopage.getId())));
			ClassesPlanEntity classesPlanEntity = classesPlanService.getOne(Wrappers.<ClassesPlanEntity>query().lambda()
				.eq(ClassesPlanEntity::getClassesId, vopage.getId()));
			if (null != classesPlanEntity) {
				TrainingPlanEntity trainingPlanEntity = trainingPlanService.getById(classesPlanEntity.getPlanId());
				if (null != trainingPlanEntity) {
					vopage.setTrainingPlanName(trainingPlanEntity.getPlanName());
					vopage.setClassesPlan(ClassesPlanWrapper.build().entityVO(classesPlanEntity));
					vopage.setTrainPlanId(trainingPlanEntity.getId());
					vopage.setIsExam(trainingPlanEntity.getIsExam());//是否需要考核(0 否，1是),如果是1，需要安排考试
				}
			}
		});
		return R.data(classesVOIPage);
	}

	/**
	 * 班级表 自定义分页
	 */
	//@PreAuth(TrainingRoleConstant.HAS_ROLE_TEACHER)
	@GetMapping("/page")
	@ApiOperationSupport(order = 3)
	@ApiOperation(value = "分页", notes = "传入classes")
	public R<IPage<ClassesVO>> page(ClassesVO classes, Query query) {
		IPage<ClassesVO> pages = classesService.selectClassesPage(Condition.getPage(query), classes);
		return R.data(pages);
	}

	/**
	 * 班级表 新增
	 */
	//@PreAuth(TrainingRoleConstant.HAS_ROLE_TEACHER)
	@PostMapping("/save")
	@ApiOperationSupport(order = 4)
	@ApiOperation(value = "新增", notes = "传入classes")
	@ServiceLog(value = TrainingOperateConstant.CLASSES, operate = TrainingOperateConstant.ADD, describe = "班级新增")
	@Transactional(rollbackFor = Exception.class)
	public R save(@Valid @RequestBody ClassesVO classes) {
		classesService.save(classes);
		ClassesPlanEntity classesPlanEntity = new ClassesPlanEntity();
		classesPlanEntity.setClassesId(classes.getId());
		classesPlanEntity.setPlanId(classes.getTrainPlanId());
		classesPlanService.save(classesPlanEntity);
		return R.success("操作成功");
	}

	/**
	 * 班级表 修改
	 */
	//@PreAuth(TrainingRoleConstant.HAS_ROLE_TEACHER)
	@PostMapping("/update")
	@ApiOperationSupport(order = 5)
	@ApiOperation(value = "修改", notes = "传入classes")
	@ServiceLog(value = TrainingOperateConstant.CLASSES, operate = TrainingOperateConstant.UPDATE, describe = "班级修改")
	@Transactional(rollbackFor = Exception.class)
	public R update(@Valid @RequestBody ClassesVO classes) {
		classesPlanService.remove(Wrappers.<ClassesPlanEntity>query().lambda().eq(ClassesPlanEntity::getClassesId, classes.getId()));
		ClassesPlanEntity classesPlanEntity = new ClassesPlanEntity();
		classesPlanEntity.setClassesId(classes.getId());
		classesPlanEntity.setPlanId(classes.getTrainPlanId());

		classesPlanService.save(classesPlanEntity);
		return R.status(classesService.updateById(classes));
	}


	/**
	 * 班级表 删除
	 */
	//@PreAuth(TrainingRoleConstant.HAS_ROLE_TEACHER)
	@PostMapping("/remove")
	@ApiOperationSupport(order = 7)
	@ApiOperation(value = "逻辑删除", notes = "传入ids")
	@ServiceLog(value = TrainingOperateConstant.CLASSES, operate = TrainingOperateConstant.DELETE, describe = "班级删除")
	@Transactional(rollbackFor = Exception.class)
	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
		classesUserService.remove(Wrappers.<ClassesUserEntity>query().lambda().in(ClassesUserEntity::getClassesId, Func.toLongList(ids)));
		return R.status(classesService.deleteLogic(Func.toLongList(ids)));
	}

	/**
	 * 导出数据
	 */
	@GetMapping("/export-classes")
	@ApiOperationSupport(order = 9)
	@ApiOperation(value = "导出数据", notes = "传入classes")
	public void exportClasses(@ApiIgnore @RequestParam Map<String, Object> classes, BladeUser bladeUser, HttpServletResponse response) {
		QueryWrapper<ClassesEntity> queryWrapper = Condition.getQueryWrapper(classes, ClassesEntity.class);
		//if (!AuthUtil.isAdministrator()) {
		//	queryWrapper.lambda().eq(Classes::getTenantId, bladeUser.getTenantId());
		//}
		queryWrapper.lambda().eq(ClassesEntity::getIsDeleted, BladeConstant.DB_NOT_DELETED);
		List<ClassesExcel> list = classesService.exportClasses(queryWrapper);
		ExcelUtil.export(response, "班级表数据" + DateUtil.time(), "班级表数据表", list, ClassesExcel.class);
	}


	@GetMapping("/trainees-score")
	@ApiOperationSupport(order = 10)
	@ApiOperation(value = "指定班级受训人员的成绩分页", notes = "传入班级id")
	public R traineesScorelist(Long id, Query query) {
		ClassesPlanEntity classesPlanEntity = classesPlanService.getOne(Wrappers.<ClassesPlanEntity>query().lambda().eq(ClassesPlanEntity::getClassesId, id));

		//1.获取试卷发布id
		PaperReleaseEntity paperReleaseEntity = paperReleaseService.getOne(Wrappers.<PaperReleaseEntity>query()
			.lambda().eq(PaperReleaseEntity::getId, classesPlanEntity.getPlanId()));
		//2.获取用户答题成绩
//		IPage<ClassesEntity> pages = classesService.page(Condition.getPage(query), Condition.getQueryWrapper(classes, ClassesEntity.class));
//
		return R.data("成功");
	}

	private final IReleaseExamUserService releaseExamUserService;

	@GetMapping("/push-exam")
	@ApiOperationSupport(order = 11)
	@ApiOperation(value = "推送考试", notes = "传入考试发布id-releaseId,班级id-id")
	@Transactional(rollbackFor = Exception.class)
	public R traineesScorelist(ClassesEntity entity) {
		if (ObjectUtil.isEmpty(entity.getId())) throw new TrainingServiceException("请选择班级");
		if (ObjectUtil.isEmpty(entity.getReleaseId())) throw new TrainingServiceException("请选择一门考试");
		ClassesEntity classesEntity = classesService.getById(entity.getId());

		List<Long> classesList = new ArrayList<>();
		classesList.add(entity.getId());
		UserBindingBo bindingBo = new UserBindingBo();
		bindingBo.setType(2);
		bindingBo.setBindingId(entity.getReleaseId());
		bindingBo.setClassesList(classesList);

		if (ObjectUtil.isNotEmpty(classesEntity.getReleaseId())) {//如果已有考试，则需要删掉原考试有包含这个班级的学员记录
			List<ClassesUserEntity> classesUserEntityList = classesUserService.list(Wrappers.<ClassesUserEntity>query().lambda().eq(ClassesUserEntity::getClassesId, entity.getId()));
			if (CollectionUtil.isNotEmpty(classesUserEntityList)) {
				releaseExamUserService.remove(Wrappers.<ReleaseExamUserEntity>query().lambda()
					.in(ReleaseExamUserEntity::getUserId, classesUserEntityList.stream().map(ClassesUserEntity::getUserId).collect(Collectors.toList()))
					.eq(ReleaseExamUserEntity::getReleaseId, entity.getReleaseId()));
			}
		}
		userBindingService.addUserBinding(bindingBo);
		classesService.updateById(entity);
		return R.success("推送成功");
	}

	private final IUserBaseService userBaseService;

	/**
	 * 班级成绩
	 * 在班级管理有推考试的才能查到
	 */
	@GetMapping("/classes-score")
	@ApiOperationSupport(order = 12)
	@ApiOperation(value = "班级成绩", notes = "传入班级id")
	public R classesScore(Long id) {
		ClassesEntity classesEntity = classesService.getById(id);
		if (null != classesEntity && null != classesEntity.getReleaseId()) {
			Long releaseId = classesEntity.getReleaseId();
			PaperReleaseEntity paperReleaseEntity = paperReleaseService.getById(releaseId);
			if (null==paperReleaseEntity)return R.success("暂无成绩数据");

			List<ClassesUserEntity> classesUserEntityList = classesUserService.queryByClassId(id);
			if (CollectionUtil.isNotEmpty(classesUserEntityList)) {//班级学员不能为空
				Map<String, Object> resultMap = new HashMap<>();
				DecimalFormat df = new DecimalFormat("0.##");//保留有意义的小数点后两位 例如0.1
				List<PaperAnswerEntity> paperAnswerEntityList = answerService.list(Wrappers.<PaperAnswerEntity>query().lambda()
					.eq(PaperAnswerEntity::getExamineType, 2)
					.eq(PaperAnswerEntity::getPaperReleaseId, releaseId)
					.in(PaperAnswerEntity::getUserId, classesUserEntityList.stream().map(ClassesUserEntity::getUserId).collect(Collectors.toList()))
					.orderByDesc(PaperAnswerEntity::getScore));

				if (CollectionUtil.isNotEmpty(paperAnswerEntityList)) {
					resultMap.put("releaseName", paperReleaseEntity.getReleaseName());//考试名称

					//试卷总分、合格分数、平均分、最高分、最低分、合格人数、不合格人数、达标率、优良率，优秀是试卷总分的9成，良好是试卷总分的8成
					resultMap.put("totalScore", paperReleaseEntity.getTotalScore());//试卷总分
					resultMap.put("passScore", paperReleaseEntity.getPassingScore());//合格分数

					DoubleSummaryStatistics collect = paperAnswerEntityList.stream()
						.collect(Collectors.summarizingDouble(PaperAnswerEntity::getScore));
					double average = collect.getAverage();
					double max = collect.getMax();
					double min = collect.getMin();
					double count = collect.getCount();
					resultMap.put("averageScore", average);//平均分
					resultMap.put("maxScore", max);//最高分
					resultMap.put("minScore", min);//最低分

					List<PaperAnswerEntity> passList = paperAnswerEntityList.stream()
						.filter(paperAnswerEntity -> paperAnswerEntity.getScore() >= paperReleaseEntity.getPassingScore()).collect(Collectors.toList());
					resultMap.put("passNum", passList.size());//合格人数
					resultMap.put("noPassNum",count- passList.size());//不合格人数
					resultMap.put("passRate", df.format(passList.size() / count * 1.0 * 100) + "%");//合格率

					List<PaperAnswerEntity> mediumList = paperAnswerEntityList.stream()
						.filter(paperAnswerEntity -> paperAnswerEntity.getScore() >= paperReleaseEntity.getTotalScore() * 0.8).collect(Collectors.toList());
					resultMap.put("mediumNum", mediumList.size());//良好人数
					resultMap.put("mediumRate", df.format(mediumList.size() / count * 1.0 * 100) + "%");//良好率

					List<PaperAnswerEntity> excellentList = paperAnswerEntityList.stream()
						.filter(paperAnswerEntity -> paperAnswerEntity.getScore() >= paperReleaseEntity.getTotalScore() * 0.9).collect(Collectors.toList());
					resultMap.put("excellentNum", excellentList.size());//优秀人数
					resultMap.put("excellentRate", df.format(excellentList.size() / count * 1.0 * 100) + "%");//优秀率

					List<PaperAnswerVO> scoreList = paperAnswerEntityList.stream().map(paperAnswerEntity -> {
						PaperAnswerVO paperAnswerVO = AnswerWrapper.build().entityVO(paperAnswerEntity);

						UserBaseEntity userBaseEntity = userBaseService.selectByUserId(paperAnswerEntity.getUserId());
						if (null != userBaseEntity) {
							paperAnswerVO.setRealName(userBaseEntity.getUserName());//用户姓名
							paperAnswerVO.setIdCard(userBaseEntity.getUserNumber());//用户身份证
						}

						return paperAnswerVO;
					}).collect(Collectors.toList());
					resultMap.put("scoreList", scoreList);//成绩列表
					return R.data(resultMap);
				}

			}
		}
		return R.success("暂无成绩数据");
	}


	@GetMapping("/export-classes-score")
	@ApiOperationSupport(order = 13)
	@ApiOperation(value = "导出班级成绩", notes = "传入班级id")
//	public void exportTrainingPlan(@ApiParam(value = "主键集合", required = true) @RequestParam String ids, HttpServletResponse response) {
	public void exportClassesScore(Long id, HttpServletResponse response) {
		List<ClassesScoreExcel> list=new ArrayList<>();
		ClassesEntity classesEntity = classesService.getById(id);
		if (null != classesEntity && null != classesEntity.getReleaseId()) {
			Long releaseId = classesEntity.getReleaseId();
			PaperReleaseEntity paperReleaseEntity = paperReleaseService.getById(releaseId);
			List<ClassesUserEntity> classesUserEntityList = classesUserService.queryByClassId(id);
			if (CollectionUtil.isNotEmpty(classesUserEntityList)) {//班级学员不能为空
				List<PaperAnswerEntity> paperAnswerEntityList = answerService.list(Wrappers.<PaperAnswerEntity>query().lambda()
					.eq(PaperAnswerEntity::getExamineType, 2)
					.eq(PaperAnswerEntity::getPaperReleaseId, releaseId)
					.in(PaperAnswerEntity::getUserId, classesUserEntityList.stream().map(ClassesUserEntity::getUserId).collect(Collectors.toList()))
					.orderByDesc(PaperAnswerEntity::getScore));

				if (CollectionUtil.isNotEmpty(paperAnswerEntityList)) {
					list = paperAnswerEntityList.stream().map(paperAnswerEntity -> {
						ClassesScoreExcel excel=new ClassesScoreExcel();
						UserBaseEntity userBaseEntity = userBaseService.selectByUserId(paperAnswerEntity.getUserId());
						if (null != userBaseEntity) {
							excel.setUserName(userBaseEntity.getUserName());
						}
						excel.setClassesName(classesEntity.getClassesName());
						excel.setPassingScore(paperReleaseEntity.getPassingScore());
						excel.setTotalScore(paperReleaseEntity.getTotalScore());
						excel.setScore(paperAnswerEntity.getScore());

						return excel;
					}).collect(Collectors.toList());
				}

			}
		}
		ExcelUtil.export(response, "班级成绩数据" + DateUtil.time(), "班级成绩", list, ClassesScoreExcel.class);
	}


	/**
	 * 班级-考核结果
	 * 这个班级的人的学习任务、课后作业是否都已完成
	 * id 班级id
	 */
	@GetMapping("/classes-assessment-result")
	@ApiOperationSupport(order = 14)
	@ApiOperation(value = "班级-考核结果", notes = "传入班级id")
	public R assessmentResults(Long id) {
		List<TrainingPlanReusltExcel> resultList = new ArrayList<>();
//		ClassesEntity classesEntity = classesService.getById(id);
		ClassesPlanEntity classesPlanEntity = classesPlanService.getOne(Wrappers.<ClassesPlanEntity>query().lambda().eq(ClassesPlanEntity::getClassesId, id));
		if (null == classesPlanEntity) return R.success("暂无数据");

		//获取培训计划
		TrainingPlanEntity trainingPlan = trainingPlanService.getById(classesPlanEntity.getPlanId());
		//查询该班级的下学生
		List<ClassesUserEntity> userList = classesUserService.list(Wrappers.<ClassesUserEntity>query().lambda()
			.eq(ClassesUserEntity::getClassesId, id));
		if (CollectionUtil.isEmpty(userList)) return R.success("暂无数据");

		//查询该培训计划的课程
		List<TrainingPlanCourseEntity> planCourseList = trainingPlanCourseService.list(Wrappers.<TrainingPlanCourseEntity>query().lambda()
			.eq(TrainingPlanCourseEntity::getTrainingPlanId, classesPlanEntity.getPlanId()));
		if (CollectionUtil.isEmpty(planCourseList)) return R.success("暂无数据");

		for (ClassesUserEntity user : userList) {
			boolean flag;
			String result = "通过";
			for (TrainingPlanCourseEntity planCourse : planCourseList) {
				flag = courseService.checkCourseComplete(planCourse.getCourseId(), user.getUserId());
				if (!flag) {
					result = "不通过";
					break;//如果有一门课程不通过，则表示所有都不通过
				}
			}
			TrainingPlanReusltExcel excel = new TrainingPlanReusltExcel();
			excel.setResult(result);
			excel.setPlanName(trainingPlan.getPlanName());
			UserBaseEntity userBase = userBaseService.getOne(Wrappers.<UserBaseEntity>query()
				.lambda().eq(UserBaseEntity::getUserId, user.getUserId()));
			if (null != userBase) {
				excel.setUserName(userBase.getUserName());
				excel.setIdCard(userBase.getIdCard());
			}
			resultList.add(excel);
		}
		return R.data(resultList);
	}

	/**
	 * 下拉列表
	 */
	@GetMapping("/select")
	@ApiOperationSupport(order = 20)
	@ApiOperation(value = "下拉列表", notes = "传入trainingPlan")
	public R select(@ApiIgnore @RequestParam Map<String, Object> entity) {
		QueryWrapper<ClassesEntity> queryWrapper = Condition.getQueryWrapper(entity, ClassesEntity.class);
		return R.data(classesService.list(queryWrapper));
	}


}
